Qt颜色选择器(HSV)

您所在的位置:网站首页 hsv 颜色 Qt颜色选择器(HSV)

Qt颜色选择器(HSV)

2023-09-12 19:50| 来源: 网络整理| 查看: 265

目录 引言HSV颜色空间实现思路代码实现

引言

基于Qt实现的HSV颜色选择器,效果如下: 在这里插入图片描述

HSV颜色空间

HSV(Hue, Saturation, Value)是根据颜色的直观特征创建的颜色模型,如下图所示: 在这里插入图片描述 Hue为色调,通过角度表示不同的颜色,取值范围是0°到359°。Saturation为饱和度,取值范围是0到1。Value为明度,表示颜色明暗,值越大越亮,取值范围是0到1。下述实现方案中,饱和度和明度的范围改为0到255。

实现思路

在这里插入图片描述 按照上述模型,实现的关键就是将圆锥的三维投影到二维平面,右侧滑动条表示色调Hue,从0到359。中间画布横坐标表示饱和度Saturation,从0到255,纵坐标表示明度Value,从0到255。滑动条通过修改样式表实现,画布通过paintEvent实现。

代码实现

详细代码如下:

class ColorHueBar : public QWidget { Q_OBJECT public: ColorHueBar(QWidget *parent = nullptr); ~ColorHueBar(); void setValue(int val); int value(); signals: void sig_valueChanged(int val); private: QSlider* m_slider; }; class ColorSVCanvas : public QWidget { Q_OBJECT public: ColorSVCanvas(QWidget *parent = nullptr); ~ColorSVCanvas(); bool setHue(int hue); bool setSaturationValue(int saturation, int value); bool setSaturationValue(QPoint saturationValue); QColor color(); QRect availabilityRect(); int margin(); signals: void sig_colorChanged(const QColor &color); protected: void paintEvent(QPaintEvent* ev) Q_DECL_OVERRIDE; void resizeEvent(QResizeEvent* ev) Q_DECL_OVERRIDE; bool eventFilter(QObject* obj, QEvent* ev) Q_DECL_OVERRIDE; private: QPoint valueFromPos(QPoint& pos); QPoint posFromValue(QPoint& val); private: int m_margin; int m_radius; int m_saturationMax; int m_valueMax; int m_hue; QPoint m_pos; }; class ColorChecker : public QWidget { Q_OBJECT public: ColorChecker(QWidget *parent = nullptr); ~ColorChecker(); protected: void paintEvent(QPaintEvent* ev) Q_DECL_OVERRIDE; private: int m_checkerSize; }; class ColorAlphaBar : public QWidget { Q_OBJECT public: ColorAlphaBar(QWidget *parent = nullptr); ~ColorAlphaBar(); void setColor(QColor color); QColor color(); void setValue(int alpha); signals: void sig_colorChanged(const QColor &color); protected: void resizeEvent(QResizeEvent* ev) Q_DECL_OVERRIDE; private: ColorChecker* m_checker; QSlider* m_slider; QColor m_color; int m_grooveHeight; }; class ColorWorkbench : public QDialog { Q_OBJECT public: ColorWorkbench(QWidget *parent = nullptr); ~ColorWorkbench(); void setColor(QColor color); signals: void sig_colorChanged(const QColor &color); private: QColor colorFromStr(QString str); private slots: void slot_colorDisplay(const QColor &color); void slot_colorEdit(const QString &text); private: ColorSVCanvas* m_canvas; ColorHueBar* m_hsvBar; ColorAlphaBar* m_alphaSlider; QLineEdit* m_lineEdit; QPushButton* m_clearBtn; QPushButton* m_confirmBtn; }; class ColorPicker : public QLabel { Q_OBJECT public: ColorPicker(QWidget *parent = nullptr); ~ColorPicker(); protected: void resizeEvent(QResizeEvent* ev) Q_DECL_OVERRIDE; private: void setColor(const QColor &color); private slots: void slot_showPopup(); void slot_colorChanged(const QColor &color); private: QPushButton* m_button; ColorChecker* m_checker; ColorWorkbench* m_popup; QColor m_curColor; QColor m_oriColor; }; ColorHueBar::ColorHueBar(QWidget *parent) : QWidget(parent) { m_slider = new QSlider(this); m_slider->setMaximum(359); m_slider->setFixedWidth(16); m_slider->setStyleSheet("QSlider::groove:vertical {width: 12px; \ background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, \ stop:0 hsv(0,255,255), \ stop:0.17 hsv(59,255,255), \ stop:0.33 hsv(119,255,255), \ stop:0.5 hsv(179,255,255), \ stop:0.67 hsv(239,255,255), \ stop:0.83 hsv(299,255,255), \ stop:1 hsv(359,255,255));} \ QSlider::handle:vertical { \ background: white; \ height: 4px; \ margin:0px -2px; \ border: 1px solid grey; \ border-radius: 2px;} \ QSlider::add-page:vertical {background: transparent;} \ QSlider::sub-page:vertical {background: transparent;}"); setValue(0); connect(m_slider, &QSlider::valueChanged, this, [this]{ emit sig_valueChanged(value()); }); auto mainLayout = new QHBoxLayout(this); mainLayout->setMargin(0); mainLayout->setSpacing(0); mainLayout->addWidget(m_slider); } ColorHueBar::~ColorHueBar() { } void ColorHueBar::setValue(int val) { m_slider->setValue(qAbs(val - m_slider->maximum())); } int ColorHueBar::value() { return qAbs(m_slider->value() - m_slider->maximum()); } ColorSVCanvas::ColorSVCanvas(QWidget *parent) : QWidget(parent) , m_margin(5) , m_radius(m_margin - 1) , m_saturationMax(255) , m_valueMax(255) , m_hue(0) , m_pos(QPoint(-1, -1)) { installEventFilter(this); } ColorSVCanvas::~ColorSVCanvas() { } bool ColorSVCanvas::setHue(int hue) { if(hue 359) return false; m_hue = hue; update(); emit sig_colorChanged(color()); return true; } bool ColorSVCanvas::setSaturationValue(int saturation, int value) { return setSaturationValue(QPoint(saturation, value)); } bool ColorSVCanvas::setSaturationValue(QPoint saturationValue) { if(!QRect(0,0,256,256).contains(saturationValue)) return false; m_pos = posFromValue(saturationValue); update(); emit sig_colorChanged(color()); return true; } QColor ColorSVCanvas::color() { QPoint tmpVal = valueFromPos(m_pos); QColor tmpColor; tmpColor.setHsv(m_hue, tmpVal.x(), tmpVal.y()); return tmpColor; } QRect ColorSVCanvas::availabilityRect() { QRect tmpRect(m_margin, m_margin, width() - m_margin * 2, height() - m_margin * 2); return tmpRect; } int ColorSVCanvas::margin() { return m_margin; } void ColorSVCanvas::paintEvent(QPaintEvent *) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); QRect rect = availabilityRect(); // 绘制从左到右RGB(255,255,255)到HSV(h,255,255)的渐变 QLinearGradient linearGradientH(rect.topLeft(), rect.topRight()); linearGradientH.setColorAt(0, Qt::white); QColor color; color.setHsv(m_hue, m_saturationMax, m_valueMax); linearGradientH.setColorAt(1, color); painter.fillRect(rect, linearGradientH); // 绘制顶部颜色值为RGBA(0,0,0,0)到最底部RGBA(0,0,0,255)的渐变 QLinearGradient linearGradientV(rect.topLeft(), rect.bottomLeft()); linearGradientV.setColorAt(0, QColor(0, 0, 0, 0)); linearGradientV.setColorAt(1, QColor(0, 0, 0, 255)); painter.fillRect(rect, linearGradientV); painter.setPen(QColor(Qt::darkGray)); painter.drawEllipse(m_pos, m_radius, m_radius); } void ColorSVCanvas::resizeEvent(QResizeEvent *) { if(m_pos == QPoint(-1, -1)){ setSaturationValue(255, 255); } } bool ColorSVCanvas::eventFilter(QObject *obj, QEvent *ev) { if(obj == this){ if(ev->type() == QEvent::MouseButtonPress){ if(availabilityRect().contains(mapFromGlobal(QCursor::pos()))){ m_pos = mapFromGlobal(QCursor::pos()); update(); emit sig_colorChanged(color()); } } } return QWidget::eventFilter(obj, ev); } QPoint ColorSVCanvas::valueFromPos(QPoint &pos) { QRect tmpRect = availabilityRect(); QPoint tmpPos = pos - tmpRect.topLeft(); int saturation = tmpPos.x() * m_saturationMax / tmpRect.width(); int value = qAbs(tmpPos.y() * m_valueMax / tmpRect.height() - m_valueMax); return QPoint(saturation, value); } QPoint ColorSVCanvas::posFromValue(QPoint &val) { QRect tmpRect = availabilityRect(); int tmpX = val.x() * tmpRect.width() / m_saturationMax; int tmpY = qAbs(val.y() - m_valueMax) * tmpRect.height() / m_valueMax; return QPoint(tmpX, tmpY) + tmpRect.topLeft(); } ColorChecker::ColorChecker(QWidget *parent) : QWidget(parent) , m_checkerSize(6) { } ColorChecker::~ColorChecker() { } void ColorChecker::paintEvent(QPaintEvent *ev) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); int rowCount = ev->rect().height() / m_checkerSize + 1; int colCount = ev->rect().width() / m_checkerSize + 1; for(int i=0; i QRect checkerRect(m_checkerSize * j, m_checkerSize * i, m_checkerSize, m_checkerSize); QColor checkerColor; if(((j + i % 2) % 2) == 0){ checkerColor = Qt::darkGray; }else{ checkerColor = Qt::white; } painter.fillRect(checkerRect, checkerColor); } } } ColorAlphaBar::ColorAlphaBar(QWidget *parent) : QWidget(parent) , m_grooveHeight(12) { m_checker = new ColorChecker(this); m_slider = new QSlider(Qt::Horizontal, this); m_slider->setMaximum(255); m_slider->setValue(m_slider->maximum()); m_slider->setFixedHeight(16); setColor(Qt::red); connect(m_slider, &QSlider::valueChanged, this, [this]{ emit sig_colorChanged(color()); }); auto mainLayout = new QVBoxLayout(this); mainLayout->setMargin(0); mainLayout->setSpacing(0); mainLayout->addWidget(m_slider); } ColorAlphaBar::~ColorAlphaBar() { } void ColorAlphaBar::setColor(QColor oriColor) { m_color = oriColor; m_color.setAlpha(255); QColor tmpColor(oriColor); tmpColor.setAlpha(0); m_slider->setStyleSheet(QString("QSlider::groove:horizontal { \ height: %3px; \ background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, \ stop:0 %1, \ stop:1 %2);} \ QSlider::handle:horizontal { \ background: white; \ width: 4px; \ margin: -2px 0; \ border: 1px solid grey; \ border-radius: 2px;} \ QSlider::add-page:horizontal {background: transparent;} \ QSlider::sub-page:horizontal {background: transparent;}") .arg(tmpColor.name(QColor::HexArgb)) .arg(m_color.name()) .arg(m_grooveHeight)); emit sig_colorChanged(color()); } QColor ColorAlphaBar::color() { QColor tmpColor(m_color); tmpColor.setAlpha(m_slider->value()); return tmpColor; } void ColorAlphaBar::setValue(int alpha) { m_slider->setValue(alpha); } void ColorAlphaBar::resizeEvent(QResizeEvent *) { m_checker->setGeometry(0, (height() - m_grooveHeight) / 2, width(), m_grooveHeight); } ColorWorkbench::ColorWorkbench(QWidget *parent) : QDialog(parent, Qt::Popup) { setFixedSize(320, 250); setAttribute(Qt::WA_StyledBackground); setObjectName("workbench"); setStyleSheet("#workbench{background-color:white; border:1px solid rgb(245,245,245); border-radius: 6px;}"); m_canvas = new ColorSVCanvas(this); m_canvas->setFixedSize(280, 180); m_hsvBar = new ColorHueBar(this); m_hsvBar->setFixedHeight(m_canvas->availabilityRect().height()); m_alphaSlider = new ColorAlphaBar(this); m_alphaSlider->setFixedWidth(m_canvas->availabilityRect().width()); m_lineEdit = new QLineEdit(this); m_clearBtn = new QPushButton("clear",this); m_clearBtn->setVisible(false); m_confirmBtn = new QPushButton("confirm", this); connect(m_confirmBtn, &QPushButton::clicked, this, [this]{ accept(); }); connect(m_hsvBar, &ColorHueBar::sig_valueChanged, this, [this](int val){ m_canvas->setHue(val); }); connect(m_canvas, &ColorSVCanvas::sig_colorChanged, this, [this](const QColor &color){ m_alphaSlider->setColor(color); }); connect(m_alphaSlider, &ColorAlphaBar::sig_colorChanged, this, &ColorWorkbench::slot_colorDisplay); connect(m_lineEdit, &QLineEdit::textEdited, this, &ColorWorkbench::slot_colorEdit); // 布局 auto handleLayout = new QHBoxLayout; handleLayout->addSpacing(m_canvas->margin()); handleLayout->addWidget(m_lineEdit); handleLayout->addStretch(); handleLayout->addWidget(m_clearBtn); handleLayout->addWidget(m_confirmBtn); auto alphaLayout = new QHBoxLayout; alphaLayout->setMargin(0); alphaLayout->addSpacing(m_canvas->margin()); alphaLayout->addWidget(m_alphaSlider); auto mainLayout = new QGridLayout(this); mainLayout->addWidget(m_canvas, 0, 0); mainLayout->addWidget(m_hsvBar, 0, 1); mainLayout->addLayout(alphaLayout, 1, 0); mainLayout->addLayout(handleLayout, 2, 0, 1, 2); } ColorWorkbench::~ColorWorkbench() { } void ColorWorkbench::setColor(QColor color) { m_hsvBar->setValue(color.hsvHue()); m_canvas->setSaturationValue(color.hsvSaturation(), color.value()); m_alphaSlider->setValue(color.alpha()); } QColor ColorWorkbench::colorFromStr(QString str) { QColor color(str); if(!color.isValid()){ QString tmpStr = str; QRegExp rx("[^\\d+^,^.]"); if(str.contains(rx)){ tmpStr.remove(rx); } if(!tmpStr.isEmpty()){ QStringList strList = tmpStr.split(","); if(str.contains("rgba") && strList.count() == 4){ color.setRgb(strList.at(0).toInt(), strList.at(1).toInt(), strList.at(2).toInt()); if(strList.at(3).toDouble()>1){ color.setAlpha(strList.at(3).toInt()); }else{ color.setAlphaF(strList.at(3).toDouble()); } } else if(str.contains("rgb") && strList.count() == 3){ color.setRgb(strList.at(0).toInt(), strList.at(1).toInt(), strList.at(2).toInt()); } else if(str.contains("hsv") && strList.count() == 3){ color.setHsv(strList.at(0).toInt(), strList.at(1).toInt(), strList.at(2).toInt()); } } } return color; } void ColorWorkbench::slot_colorDisplay(const QColor& color) { QRegExp reg("(\\.){0,1}0+$");// 去除末尾0 m_lineEdit->setText(QString("rgba(%1, %2, %3, %4)") .arg(color.red()) .arg(color.green()) .arg(color.blue()) .arg(QString::number(color.alphaF(), 'f', 2).replace(reg, ""))); emit sig_colorChanged(color); } void ColorWorkbench::slot_colorEdit(const QString &text) { QColor color = colorFromStr(text); if(color.isValid()){ disconnect(m_alphaSlider, &ColorAlphaBar::sig_colorChanged, this, &ColorWorkbench::slot_colorDisplay); setColor(color); connect(m_alphaSlider, &ColorAlphaBar::sig_colorChanged, this, &ColorWorkbench::slot_colorDisplay); emit sig_colorChanged(color); } } ColorPicker::ColorPicker(QWidget *parent) : QLabel(parent) { m_checker = new ColorChecker(this); m_popup = new ColorWorkbench(this); connect(m_popup, &ColorWorkbench::sig_colorChanged, this, &ColorPicker::slot_colorChanged); connect(m_popup, &QDialog::finished, this, [this](int result){ if(result == QDialog::Accepted){ m_oriColor = m_curColor; } else{ setColor(m_oriColor); } }); m_button = new QPushButton("v", this); m_button->setFixedSize(30, 30); connect(m_button, &QPushButton::pressed, this, &ColorPicker::slot_showPopup); setFixedSize(40, 40); setStyleSheet(QString("QLabel{border:1px solid %1; border-radius: 4px; background-color: %2;}") .arg(QColor(230, 230, 230).name()) .arg(QColor(Qt::white).name())); setColor(QColor(255,0,0,150)); auto mainLayout = new QHBoxLayout(this); mainLayout->setMargin(0); mainLayout->addWidget(m_button); } ColorPicker::~ColorPicker() { } void ColorPicker::resizeEvent(QResizeEvent *) { m_checker->setGeometry(m_button->geometry()); } void ColorPicker::setColor(const QColor &color) { m_curColor = color; m_button->setStyleSheet(QString("QPushButton{border:1px solid %1; background-color:%2}") .arg(QColor(152,152,152).name()) .arg(color.name(QColor::HexArgb))); } void ColorPicker::slot_showPopup() { m_oriColor = m_curColor; m_popup->setColor(m_oriColor); QPoint tmpPos = mapToGlobal(m_button->geometry().center()); tmpPos += QPoint(-m_popup->width() / 2, m_button->height() / 2 + 5); m_popup->move(tmpPos); m_popup->open(); } void ColorPicker::slot_colorChanged(const QColor &color) { if (m_popup->isVisible()) { setColor(color); } }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3